﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System8ToyMC;
using System.Windows.Controls.DataVisualization.Charting;
using System.Collections.ObjectModel;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;

namespace t_System8ToyMCControls
{
    [TestClass]
    public class t_HistogramArea : PresentationTest
    {
        HistogramArea _val;
        RandomVariableList _rval;

        [TestInitialize]
        public void Setup()
        {
            _val = new HistogramArea();
            _rval = _val.FindName("RVarList") as RandomVariableList;
            TestPanel.Children.Add(_val);
        }

        [TestMethod]
        public void TestCTor()
        {
            Assert.IsNotNull(_val);
            Assert.IsNotNull(_rval);
        }

        [TestMethod]
        [Asynchronous]
        public void TestSimpleCalculate()
        {
            EnqueueCallback(() => _val.Calculate(NiceS8()));
            EnqueueDelay(1000);
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(1000)]
        public void TestAddHistogram()
        {
            Histogram h = new Histogram();
            bool loaded = false;
            h.Loaded += (o, a) => loaded = true;

            EnqueueCallback(() => _val.AddPlot1D(h, "n/Totalvalue"));
            EnqueueConditional(() => loaded);
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(1000)]
        public void TestAddTwice()
        {
            Histogram h1 = new Histogram();
            Histogram h2 = new Histogram();
            bool loaded = false;
            h2.Loaded += (o, a) => loaded = true;

            EnqueueCallback(() => _val.AddPlot1D(h1, "n/Totalvalue"));
            EnqueueCallback(() => _val.AddPlot1D(h2, "n/Totalvalue"));
            EnqueueConditional(() => loaded);
            EnqueueCallback(() => Assert.IsNull(h1.Parent, "Parent object should have been null for old object"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestRunRandom()
        {
            Histogram h = new Histogram();
            bool loaded = false;
            h.Loaded += (o, a) => loaded = true;

            Chart mainChart = h.FindName("MainChart") as Chart;
            ColumnSeries data = mainChart.Series[0] as ColumnSeries;

            EnqueueCallback(() => _val.AddPlot1D(h, "n/TotalValue"));
            EnqueueConditional(() => loaded);
            EnqueueCallback(() => _rval.AddVariable(new System8Equations.UniformS8Variable(2500) { Path = "n/TotalValue", MaxValue = 3000, MinValue = 2000 }));
            EnqueueCallback(() => _val.Calculate(NiceS8()));
            EnqueueConditional(() => data.ItemsSource != null);
            EnqueueConditional(() => (data.ItemsSource as Histogram.BinData[]).Length > 0);
            EnqueueCallback(() => Assert.IsTrue(CountBinsFilled(h)>3, "Non zero bins are too small!"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestRunAndClear()
        {
            Histogram h = new Histogram();
            bool loaded = false;
            h.Loaded += (o, a) => loaded = true;

            Button clear = _rval.FindName("ClearButton") as Button;
            ButtonAutomationPeer buttonPeer = new ButtonAutomationPeer(clear);
            IInvokeProvider buttonInvoker = (IInvokeProvider)buttonPeer;

            Chart mainChart = h.FindName("MainChart") as Chart;
            ColumnSeries data = mainChart.Series[0] as ColumnSeries;

            ///
            /// Load up a plot and fill it with some variable
            /// 

            EnqueueCallback(() => _val.AddPlot1D(h, "n/TotalValue"));
            EnqueueConditional(() => loaded);
            EnqueueCallback(() => _rval.AddVariable(new System8Equations.UniformS8Variable(2500) { Path = "n/TotalValue", MaxValue = 3000, MinValue = 2000 }));
            EnqueueCallback(() => _val.Calculate(NiceS8()));
            EnqueueConditional(() => data.ItemsSource != null);
            Histogram.BinData[] oldData = null;
            EnqueueCallback(() => oldData = data.ItemsSource as Histogram.BinData[]);

            ///
            /// Now, clear it out and wait for an update
            /// 

            EnqueueCallback(() => buttonInvoker.Invoke());
            EnqueueConditional(() => oldData != (data.ItemsSource as Histogram.BinData[]));
            EnqueueCallback(() => Assert.AreEqual(1, CountBinsFilled(h), "After clear expect only a single bin filled!"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestNewPlotFilledAutomatically()
        {
            Histogram h = new Histogram();
            bool loaded = false;
            h.Loaded += (o, a) => loaded = true;

            Chart mainChart = h.FindName("MainChart") as Chart;
            ColumnSeries data = mainChart.Series[0] as ColumnSeries;

            EnqueueCallback(() => _val.Calculate(NiceS8()));
            EnqueueCallback(() => _val.AddPlot1D(h, "n/TotalValue"));
            EnqueueConditional(() => loaded);
            EnqueueConditional(() => data.ItemsSource != null);
            EnqueueConditional(() => (data.ItemsSource as Histogram.BinData[]).Length > 0);
            EnqueueCallback(() => Assert.AreEqual(1, CountBinsFilled(h), "Non zero bins are too small!"));
            EnqueueTestComplete();
        }

        [TestMethod]
        [Asynchronous]
        [Timeout(2000)]
        public void TestNewVaryFilledAutomatically()
        {
            Histogram h = new Histogram();
            bool loaded = false;
            h.Loaded += (o, a) => loaded = true;

            Chart mainChart = h.FindName("MainChart") as Chart;
            ColumnSeries data = mainChart.Series[0] as ColumnSeries;

            EnqueueCallback(() => _val.AddPlot1D(h, "n/TotalValue"));
            EnqueueConditional(() => loaded);
            var startPoint = NiceS8();
            EnqueueCallback(() => _val.Calculate(startPoint));
            EnqueueConditional(() => data.ItemsSource != null);
            object oldData = null;
            EnqueueCallback(() => oldData = data.ItemsSource);
            EnqueueConditional(() => (data.ItemsSource as Histogram.BinData[]).Length > 0);
            EnqueueCallback(() => Assert.AreEqual(1, CountBinsFilled(h), "Non zero bins are too small!"));
            EnqueueCallback(() => _rval.AddVariable(new System8Equations.UniformS8Variable(startPoint.n.Total) { Path = "n/TotalValue", MaxValue = startPoint.n.Total*1.1, MinValue = startPoint.n.Total*0.9 }));
            EnqueueConditional(() => oldData != data.ItemsSource);
            EnqueueCallback(() => Assert.IsTrue(CountBinsFilled(h)>3, "Expected a number of bins to be filled (see only " + CountBinsFilled(h) + " bins)"));

            EnqueueTestComplete();
        }

        /// <summary>
        /// CHeck to see that at least 3 bins are filled by items.
        /// </summary>
        /// <param name="h"></param>
        /// <returns></returns>
        public int CountBinsFilled(Histogram h)
        {
            Chart mainChart = h.FindName("MainChart") as Chart;
            ColumnSeries data = mainChart.Series[0] as ColumnSeries;

            int count = 0;
            foreach (var bin in (data.ItemsSource as Histogram.BinData[]))
            {
                if (bin.Content > 0)
                {
                    count++;
                }
            }
            return count;
        }

        /// <summary>
        /// Generate some nice template for the s8 eqns.
        /// </summary>
        /// <returns></returns>
        public System8Equations.S8Equations NiceS8()
        {
            System8Equations.S8Equations eqn = new System8Equations.S8Equations();

            eqn.n.Bottom = 10000;
            eqn.n.Charm = 10000;
            eqn.n.Light = 10000;

            eqn.n1.Bottom = 5000;
            eqn.n1.Charm = 5000;
            eqn.n1.Light = 5000;

            eqn.n2.Bottom = 5000;
            eqn.n2.Charm = 5000;
            eqn.n2.Light = 5000;

            eqn.n12.Bottom = 2500;
            eqn.n12.Charm = 2500;
            eqn.n12.Light = 2500;

            eqn.p.Bottom = 10000;
            eqn.p.Charm = 10000;
            eqn.p.Light = 10000;

            eqn.p1.Bottom = 5000;
            eqn.p1.Charm = 5000;
            eqn.p1.Light = 5000;

            eqn.p2.Bottom = 5000;
            eqn.p2.Charm = 5000;
            eqn.p2.Light = 5000;

            eqn.p12.Bottom = 2500;
            eqn.p12.Charm = 2500;
            eqn.p12.Light = 2500;

            return eqn;
        }
    }
}